/**
 * ES6之前，对象的属性名都是字符串形式，容易造成属性名冲突
 * 主要使用场景：当需要向一个对象中新增属性时，担心新增的属性会覆盖原有的属性，因为并不知道源对象中有没有同名属性
 * Symbol是专门来解决这个问题的，用来生成一个独一无二的值
 * ES10/ES2019新增了Symbol值在创建时可以传入一个描述符(description)的特性
 */
const s = Symbol('this is a description')
//可以获取描述符
console.log(s.description)

/**
 * 将Symbol值作为对象的key有三种方式
 */
const s1 = Symbol('s1_Symbol')
const s2 = Symbol('s2_Symbol')
const s3 = Symbol('s3_Symbol')

/**
 * 1. 定义字面量直接使用，使用计算属性
 */
const obj = {
  name: 'dd',
  age: 19,
  [s1]: 'abc',
}

/**
 * 2.属性名赋值，使用类似索引的赋值方式
 */
obj[s2] = 'bcd'

/**
 * 3.使用Object.defineProperty
 */
Object.defineProperty(obj, s3, {
  configurable: true,
  enumerable: true,
  writable: true,
  value: 'cde',
})

console.log(obj)
//{
//   name: 'dd',
//   age: 19,
//   [Symbol(s1_Symbol)]: 'abc',
//   [Symbol(s2_Symbol)]: 'bcd',
//   [Symbol(s3_Symbol)]: 'cde'
// }

/**
 * 注意: Symbol值定义的key值在遍历/Object.keys()/Object.getPrototype时是获取不到这些Symbol值得
 * 需要使用Object.getOwnPropertySymbols()方法来获取所有Symbol定义的key
 */
console.log(Object.keys(obj)) //[ 'name', 'age' ]
console.log(Object.getOwnPropertyNames(obj)) //[ 'name', 'age' ]
console.log(Object.getOwnPropertySymbols(obj)) //[ Symbol(s1_Symbol), Symbol(s2_Symbol), Symbol(s3_Symbol) ]

/**
 * 如果希望Symbol创建出来的值是一样的,也有办法
 * Symbol.for(key)
 *  - 只要key一样，创建出来的值就完全一样
 * Symbol.keyFor()
 *  - 用于获取Symbol值得key
 * 只能用于全局注册，使用普通Symbol()创建的符号不会加入全局注册表
 */
const sa = Symbol.for('aaa')
const sb = Symbol.for('aaa')
const sc = Symbol('ccc')

console.log(sa === sb) //true
console.log(Symbol.keyFor(sa)) //aaa
console.log(Object.getOwnPropertyDescriptors(Symbol.prototype))
console.log(Symbol.keyFor(sc)) //undefined
